/////////////////////////////////////////////////////////////////////////////////////
/*
    OLED用到的接口
    MOSI    PA7     数据输入。
    CLK     PA5     时钟。
    DC      PB0     拉高为数据，拉低为命令，没有接上拉电阻。
    CS1     PB1     片选，拉低时接受输入。

    字库用到的接口
    SI      PA7     字库数据输入，与OLED共用。
    CLK     PA5     字库时针与OLED共用。
    CS2     PB10    片选，拉低时接受输入。
    SO      PA4     字库数据输出。
*/
/////////////////////////////////////////////////////////////////////////////////////
#include "oled.h"

unsigned long fontaddr = 0;

//写指令到LCD模块
void transfer_command_lcd(int data1)
{
    char i;
    cmd_mode;
    enable_oled;
    for(i = 0; i < 8; i++)
    {
        clk_l;
        if(data1 & 0x80)
        {
            input_h;
        }
        else
        {
            input_l;
        }
        clk_h;
        data1 <<= 1;
    }
    disable_oled;
}

//写数据到LCD模块
void transfer_data_lcd(int data1)
{
    char i;
    data_mode;
    enable_oled;
    for(i = 0; i < 8; i++)
    {
        clk_l;
        if(data1 & 0x80)
        {
            input_h;
        }
        else
        {
            input_l;
        }
        clk_h;
        data1 <<= 1;
    }
    disable_oled;
}

//LCD模块初始化
void initial_lcd()
{
    enable_oled;
    transfer_command_lcd(0xAE);//关闭显示
    transfer_command_lcd(0x20);//设置显存中数据格式
    transfer_command_lcd(0x10);//按页显示模式，从上到下分为8页，每页8行
    transfer_command_lcd(0xb0);//竖直方向从第0页开始显示
    transfer_command_lcd(0xc8);//Set COM Output Scan Direction
    transfer_command_lcd(0x00);//水平方向从哪一个点开始，低四位
    transfer_command_lcd(0x10);//水平方向从哪一个点开始，高四位
    transfer_command_lcd(0x40);//--set start line address
    transfer_command_lcd(0x81);//--set contrast control register
    transfer_command_lcd(0xFF);
    transfer_command_lcd(0xa1);//--set segment re-map 0 to 127
    transfer_command_lcd(0xa6);//--set normal display
    transfer_command_lcd(0xa8);//--set multiplex ratio(1 to 64)
    transfer_command_lcd(0x3F);//
    transfer_command_lcd(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    transfer_command_lcd(0xd3);//-set display offset
    transfer_command_lcd(0x00);//-not offset
    transfer_command_lcd(0xd5);//--set display clock divide ratio/oscillator frequency
    transfer_command_lcd(0xf0);//--set divide ratio
    transfer_command_lcd(0xd9);//--set pre-charge period
    transfer_command_lcd(0x22);//
    transfer_command_lcd(0xda);//--set com pins hardware configuration
    transfer_command_lcd(0x12);
    transfer_command_lcd(0xdb);//--set vcomh
    transfer_command_lcd(0x20);//0x20,0.77xVcc
    transfer_command_lcd(0x8d);//--set DC-DC enable
    transfer_command_lcd(0x14);//
    transfer_command_lcd(0xaf);//打开显示
    disable_oled;
}

void lcd_address(unsigned char page, unsigned char column)
{
    //设置页地址
    transfer_command_lcd(0xb0 + column);
    //设置列地址的高4位
    transfer_command_lcd(((page & 0xf0) >> 4) | 0x10);
    //设置列地址的低4位
    transfer_command_lcd((page & 0x0f) | 0x00);
}

void clear_screen()
{
    unsigned char i, j;
    enable_oled;
    for(i = 0; i < 8; i++)
    {
        transfer_command_lcd(0xb0 + i);
        transfer_command_lcd(0x00);
        transfer_command_lcd(0x10);
        for(j = 0; j < 128; j++)
        {
            transfer_data_lcd(0x00);
        }
    }
    disable_oled;
}

//送指令到晶联讯字库IC
void send_command_to_ROM( unsigned char datu )
{
    unsigned char i;
    for(i = 0; i < 8; i++ )
    {
        if(datu & 0x80)
        {
            input_h;
        }
        else
        {
            input_l;
        }
        datu = datu << 1;
        clk_l;
        clk_h;
    }
}

//从晶联讯字库IC中取汉字或字符数据（1个字节）
static unsigned char get_data_from_ROM( )
{
    unsigned char i;
    unsigned char ret_data = 0;
    clk_h;
    for(i = 0; i < 8; i++)
    {
        clk_l;
        ret_data = ret_data << 1;
        if( ROM_OUT )
        {
            ret_data++;
        }
        clk_h;
    }
    return( ret_data );
}

//从相关地址（addrHigh：地址高字节,addrMid：地址中字节,addrLow：地址低字节）中连续读出DataLen个字节的数据到 pBuff的地址
//连续读取
void get_n_bytes_data_from_ROM(unsigned char addrHigh, unsigned char addrMid, unsigned char addrLow, unsigned char *pBuff, unsigned char DataLen )
{
    unsigned char i;
    enable_zk;
    clk_l;
    send_command_to_ROM( 0x03 );
    send_command_to_ROM( addrHigh );
    send_command_to_ROM( addrMid );
    send_command_to_ROM( addrLow );
    for(i = 0; i < DataLen; i++ )
    {
        *(pBuff + i) = get_data_from_ROM();
    }
    disable_zk;
}

//显示128x64点阵图像
void display_128x64(const unsigned char *dp)
{
    unsigned int i, j;
    enable_oled;
    for(j = 0; j < 8; j++)
    {
        lcd_address(0, j);
        for (i = 0; i < 128; i++)
        {
            transfer_data_lcd( *dp );//写数据到LCD,每写完一个8位的数据后列地址自动加1
            dp++;
        }
    }
    disable_oled;
}


//显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标
void display_graphic_16x16(unsigned int page, unsigned int column, const unsigned char *dp)
{
    unsigned int i, j;
    enable_oled;
    for(j = 2; j > 0; j--)
    {
        lcd_address(column, page);
        for (i = 0; i < 16; i++)
        {
            transfer_data_lcd(*dp);//写数据到LCD,每写完一个8位的数据后列地址自动加1
            dp++;
        }
        page++;
    }
    disable_oled;
}

//显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标
void display_graphic_8x16(unsigned int page, unsigned char column, unsigned char *dp)
{
    unsigned int i, j;
    enable_oled;
    for(j = 2; j > 0; j--)
    {
        lcd_address(column, page);
        for(i = 0; i < 8; i++)
        {
            transfer_data_lcd(*dp);//写数据到LCD,每写完一个8位的数据后列地址自动加1
            dp++;
        }
        page++;
    }
    disable_oled;
}

//显示5*7点阵图像、ASCII, 或5x7点阵的自造字符、其他图标
void display_graphic_5x7(unsigned int page, unsigned char column, unsigned char *dp)
{
    unsigned int col_cnt;
    unsigned char page_address;
    unsigned char column_address_L, column_address_H;
    page_address = 0xb0 + page;
    enable_oled;
    column_address_L = (column & 0x0f);
    column_address_H = ((column >> 4) & 0x0f) + 0x10;
    transfer_command_lcd(page_address);         /*Set Page Address*/
    transfer_command_lcd(column_address_H);     /*Set MSB of column Address*/
    transfer_command_lcd(column_address_L);     /*Set LSB of column Address*/
    for (col_cnt = 0; col_cnt < 6; col_cnt++)
    {
        transfer_data_lcd(*dp);
        dp++;
    }
    disable_oled;
}

//显示5*7的字符串
void display_string_5x7(unsigned char y, unsigned char x, unsigned char *text)
{
    unsigned char i = 0;
    unsigned char addrHigh, addrMid, addrLow ;
    unsigned char fontbuf[8];
    while((text[i] > 0x00))
    {
        if(( text[i] >= 0x20 ) && ( text[i] <= 0x7e ))
        {
            fontaddr = (text[i] - 0x20) * 8 + 0x3bfc0;
            addrHigh = (fontaddr & 0xff0000) >> 16;
            addrMid = (fontaddr & 0xff00) >> 8;
            addrLow = fontaddr & 0xff;
            get_n_bytes_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 8);
            display_graphic_5x7(y, x, fontbuf);
            i += 1;
            x += 6;
        }
        else
        {
            i++;
        }
    }
}

//显示GB2312字符串
void display_GB2312_string(unsigned char y, unsigned char x, unsigned char *text)
{
    unsigned char i = 0;
    unsigned char addrHigh, addrMid, addrLow;
    unsigned char fontbuf[32];
    while((text[i] > 0x00))
    {
        if((( text[i] >= 0xb0 ) && ( text[i] <= 0xf7 )) && ( text[i + 1] >= 0xa1))
        {
            fontaddr = ((unsigned long)(text[i] - 0xb0) * 94 + (text[i + 1] - 0xa1) + 846) * 32;
            addrHigh = (fontaddr & 0xff0000) >> 16;     /*地址的高8位,共24位*/
            addrMid = (fontaddr & 0xff00) >> 8;         /*地址的中8位,共24位*/
            addrLow = fontaddr & 0xff;                  /*地址的低8位,共24位*/
            get_n_bytes_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 32 );
            display_graphic_16x16(y, x, fontbuf);
            i += 2;
            x += 16;
        }
        else if((( text[i] >= 0xa1 ) && ( text[i] <= 0xa3)) && ( text[i + 1] >= 0xa1))
        {
            fontaddr = ((unsigned long)(text[i] - 0xa1) * 94 + (text[i + 1] - 0xa1)) * 32;
            addrHigh = (fontaddr & 0xff0000) >> 16;     /*地址的高8位,共24位*/
            addrMid = (fontaddr & 0xff00) >> 8;         /*地址的中8位,共24位*/
            addrLow = fontaddr & 0xff;                  /*地址的低8位,共24位*/
            get_n_bytes_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 32 );
            display_graphic_16x16(y, x, fontbuf);
            i += 2;
            x += 16;
        }
        else if(( text[i] >= 0x20) && ( text[i] <= 0x7e ))
        {
            fontaddr = ((unsigned long)(text[i] - 0x20) * 16 + 0x3cf80);
            addrHigh = (fontaddr & 0xff0000) >> 16;
            addrMid = (fontaddr & 0xff00) >> 8;
            addrLow = fontaddr & 0xff;
            get_n_bytes_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 16);
            display_graphic_8x16(y, x, fontbuf);
            i += 1;
            x += 8;
        }
        else
        {
            i++;
        }
    }
}

/*简单打印一个十进制数*/
void print_byte( unsigned char y, unsigned char x, uint8_t n, uint8_t fullOrHalf)
{
    uint8_t str[4];
    str[3] = 0;
    str[2] = n % 10 + '0';
    str[1] = ( n / 10 ) % 10 + '0';
    str[0] = ( n / 100 ) % 10 + '0';
    if(fullOrHalf == OLED_FULL)
    {
        display_GB2312_string( y, x, str );
    }
    else
    {
        display_string_5x7( y, x, str );
    }
}

/*简单打印一个十进制数*/
void print_uint16( unsigned char y, unsigned char x, uint16_t n, uint8_t fullOrHalf )
{
    uint8_t str[6];
    str[5] = 0;
    str[4] = (n / 1) % 10 + '0';
    str[3] = ( n / 10 ) % 10 + '0';
    str[2] = ( n / 100 ) % 10 + '0';
    str[1] = ( n / 1000 ) % 10 + '0';
    str[0] = ( n / 10000 ) % 10 + '0';
    if(fullOrHalf == OLED_FULL)
    {
        display_GB2312_string( y, x, str );
    }
    else
    {
        display_string_5x7( y, x, str );
    }
}

/*简单打印一个十进制数*/
void print_char( unsigned char y, unsigned char x, unsigned char n, uint8_t fullOrHalf )
{
    uint8_t str[5];
    str[0] =  n & 0x80 ? '-' : '+';             //正负
    n = n & 0x80 ? ~n + 1 : n;                  //补码转换
    str[1] = ( n / 100 ) % 10 + '0';            //百位
    str[2] = ( n / 10 ) % 10 + '0';             //十位
    str[3] = n % 10 + '0';                      //个位
    str[4] = 0;                                 //末位0
    if(fullOrHalf == OLED_FULL)
    {
        display_GB2312_string( y, x, str );
    }
    else
    {
        display_string_5x7( y, x, str );
    }
}

/*打印一个十六进制数*/
void print_Hex1( unsigned char y, unsigned char x, unsigned char n, uint8_t fullOrHalf )
{
    const unsigned char tab[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    uint8_t str[3];
    str[2] = 0;
    str[1] = tab[n & 0x0F];
    str[0] = tab[n >> 4];
    if(fullOrHalf == OLED_FULL)
    {
        display_GB2312_string( y, x, str );
    }
    else
    {
        display_string_5x7( y, x, str );
    }
}

